package model;

import java.util.ArrayList;
import java.util.HashMap;

import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * Basic model framework for storing data
 * @author rmeyers
 *
 */
public abstract class AbstractModel implements IModel {
	
	private static final Logger logger = Logger.getLogger(AbstractModel.class.getName());
	
	//Below, the String key for each HashMap is the variable's name.	
	protected HashMap<String, Double> variables = new HashMap<String, Double>();	
	protected ArrayList<String> appliedModifiers = new ArrayList<String>();
	
	public AbstractModel() {		
	}
	
	public Double getVariable(String varName) {
		return variables.get(varName);
	}
	
	/**
	 * Accepts a new modifier string, if valid adds to list of applied modifiers, then calls variable recalculation
	 * @param modifier
	 * @return
	 */
	public boolean applyModifier(String modifier) {
		String[] piecesNewMod = modifier.split(" ");
		
		//check for valid variable
		if (variables.containsKey(piecesNewMod[1])) {
			//check if modifier already applied
			if (!appliedModifiers.contains(modifier)) {
				appliedModifiers.add(modifier);
				updateVariable(piecesNewMod[1]);
				return true;
			}
			else {
				logger.log(Level.INFO, "Modifier " + modifier + " already applied");
				return false;
			}			
		}
		else {
			logger.log(Level.INFO, "Variable " + piecesNewMod[1] + " does not exist in this model");
			return false;  //invalid variable, does not exist for this model
		}
	}
	
	/**
	 * Remove modifier from list, update relevant variable
	 * @param modifier
	 * @return
	 */
	public boolean removeModifier(String modifier) {
		boolean check = appliedModifiers.remove(modifier);
		
		if (check) {
			String[] piecesNewMod = modifier.split(" ");
			updateVariable(piecesNewMod[1]);
		}
		
		return check;
	}
	
	/**
	 * Recalculates given variable from adders
	 * @param variable
	 * @return
	 */
	private boolean updateVariable(String variable) {
		String variableNewMod = variable;

		String[] piecesOldMod;
		String sourceOldMod;
		String variableOldMod;
		String operatorOldMod;
		Double numberOldMod;		

		Double multVal = 1.0;
		Double addVal = 0.0;

		//recalculate variable value given all modifiers
		for (String line: appliedModifiers) {
			piecesOldMod = line.split(" ");

			sourceOldMod = piecesOldMod[0];
			variableOldMod = piecesOldMod[1];
			operatorOldMod = piecesOldMod[2].substring(0,0);
			numberOldMod = new Double(piecesOldMod[2].substring(1));

			if (variableOldMod.equalsIgnoreCase(variableNewMod)) { 
				if (operatorOldMod.equalsIgnoreCase("+")) {
					addVal+=numberOldMod;
				}
				else if (operatorOldMod.equalsIgnoreCase("-")) {
					addVal-=numberOldMod;
				}
				else if (operatorOldMod.equalsIgnoreCase("*")) {
					multVal*=numberOldMod;
				}
				else {
					logger.log(Level.INFO, "Bad operator: found " + operatorOldMod + " in " + line + ", must be +,-,*");
//					return false;
				}
			}			
			variables.put(variableOldMod, addVal*multVal);												
		}
		return true;	
	}
}